<?php
/**
 * Indexer.php
 *
 * @category    Madoqua
 * @package     Search
 */

/** zend search lucene */
require_once 'Zend/Search/Lucene.php';

/**
 * Madoqua_Search_Indexer
 *
 * @category    Madoqua
 * @package     Search
 * @todo move to the model layer (perhaps follow the zym path? ;))
 */
class Madoqua_Search_Indexer {

    const INDEX_PAGE = 'Page';
    const INDEX_POST = 'Post';

    /**
     * lucene indexer
     *
     * @var Zend_Search_Lucene
     */
    protected static $_indexer;

    /**
     * get the indexer
     *
     * @return Zend_Search_Lucene
     */
    public static function getIndexer() {
        if (empty(self::$_indexer)) {
            $directory = Madoqua_Application::getDataDirectory() . DIRECTORY_SEPARATOR  . 'search/';
            if (!file_exists($directory . 'count')) {
                //index doesn't exist yet
                self::$_indexer = Zend_Search_Lucene::create($directory);
                //create the index
            } else {
                self::$_indexer = Zend_Search_Lucene::open($directory);
                //create the index
            }
        }
        return self::$_indexer;
    }

    /**
     * reset the search index
     *
     * WILL DELETE THE ENTIRE INDEX!
     *
     * @return void
     */
    public static function reset()
    {
        self::$_indexer = null;
        //reset indexer

        $directory = Madoqua_Application::getDataDirectory() . DIRECTORY_SEPARATOR  . 'search/';
        $dir = new Directory($directory);

        foreach(glob($directory . '/*') as $found) {
            if (!is_dir($found)) {
                unlink($found);
            }
        }
    }

    /**
     * count the number of index changes and perform an automatic clean if necessary
     * (and the configuration allows it)
     *
     * @return void
     */
    protected static function countAndClean() {
        $directory = Madoqua_Application::getDataDirectory() . DIRECTORY_SEPARATOR  . 'search/';
        $countFile = $directory . 'count';
        //file that contains the count

        if (!file_exists($countFile)) {
            touch($countFile);
        }
        //create it if it doesn't exist (should only happen once)

        $count = @file_get_contents($countFile);
        if ($count === false) {
            throw new Exception('could not open count file: ' . $countFile);
        }
        //open the count file

        $count = (int) $count;
        $count++;
        //woo, php type magic, gotta love it

        $return = @file_put_contents($countFile, $count);
        if ($return === false) {
            throw new Exception('could not save count file: ' . $countFile);
        }
        //save the count file again with it's value one bigger

        //FIXME do some count magic
    }

    /**
     * index a blog post row
     *
     * @param Blog_Post_Row $post
     * @return void
     */
    public static function indexPost(Blog_Post_Row $post) {
        self::cleanPost($post);
        //remove old post from the index

        $document = new Zend_Search_Lucene_Document();
        //the search document

        $document->addField(Zend_Search_Lucene_Field::Text('title', $post->title));
        $document->addField(Zend_Search_Lucene_Field::Text('content', $post->content));
        $document->addField(Zend_Search_Lucene_Field::Text('slug', $post->slug));
        $document->addField(Zend_Search_Lucene_Field::Text('posted', $post->posted));
        $document->addField(Zend_Search_Lucene_Field::Keyword('post_id', $post->id));
        $document->addField(Zend_Search_Lucene_Field::Keyword('type', 'blog_post'));
        //add the relevant fields to the document

        self::getIndexer()->addDocument($document);
        //add it to the index

        self::countAndClean();
        //count and clean
    }

    /**
     * clean old post
     *
     * @param Blog_Post_Row $post
     * @return void
     */
    protected static function cleanPost(Blog_Post_Row $post) {
        $term = new Zend_Search_Lucene_Index_Term($post->id, 'post_id');
        $hits = self::getIndexer()->termDocs($term);
        foreach ($hits as $hit) {
            self::getIndexer()->delete($hit);
        };
    }

    /**
     * index a blog page row
     *
     * @param Blog_Page_Row $page
     * @return void
     */
    public static function indexPage(Blog_Page_Row $page) {
        self::cleanPage($page);
        //remove old page from the index

        $document = new Zend_Search_Lucene_Document();
        //the search document

        $document->addField(Zend_Search_Lucene_Field::Text('title', $page->title));
        $document->addField(Zend_Search_Lucene_Field::Text('content', $page->content));
        $document->addField(Zend_Search_Lucene_Field::Keyword('page_id', $page->id));
        $document->addField(Zend_Search_Lucene_Field::Keyword('type', 'blog_page'));
        //add the relevant fields to the document

        self::getIndexer()->addDocument($document);
        //add it to the index

        self::countAndClean();
        //count and clean
    }

    /**
     * clean old post
     *
     * @param Blog_Post_Row $post
     * @return void
     */
    protected static function cleanPage(Blog_Page_Row $post) {
        $term = new Zend_Search_Lucene_Index_Term($post->id, 'page_id');
        $hits = self::getIndexer()->termDocs($term);
        foreach ($hits as $hit) {
            self::getIndexer()->delete($hit);
        };
    }

    /**
     * Re-index a result set
     *
     * @param Zend_Db_Table_Rowset $rowset
     * @return bool
     */
    public static function reIndex(Zend_Db_Table_Rowset $rowset, $type = self::INDEX_POST )
    {
        $indexer = 'index' . $type;
        try {
            foreach($rowset as $row) {
                self::$indexer($row);
            }
        } catch (Exception $e) {
            return false;
        }
        return true;
    }
}